home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1990 / 06 / fried.lst < prev    next >
File List  |  1990-05-02  |  14KB  |  560 lines

  1. _ACCESSING HARDWARE FROM 80386 PROTECTED MODE: PART II_
  2. by Stephen Fried
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. #include <dos.h>    /* i.e. just like MS C */
  8. void note();
  9. main()
  10. {
  11.     note(440,500);
  12. }
  13. void note(pitch, duration)
  14. int pitch,duration;
  15. {
  16.        int u,v;
  17.         union REGS regs;
  18.         unsigned int_count,int_duration,count,int_pitch;
  19.        int_pitch = 1190000/pitch;
  20.         int_duration = (duration*1821)/10000;
  21.         regs.x.ax = 0;                          /* call timer */
  22.         int86(0x1a, ®s, ®s);
  23.         int_count = regs.x.dx;  /* internal count = lowest 16-bits of time*/
  24.         u = inp(0x61) | 3;    /* Turn on channel 2 of 8255 using port 61h */
  25.         outp(0x61,u);         /* send byte to back */
  26.         outp(0x43,0xb6);      /* set up I/O register */
  27.         outp(0x42,(char) int_pitch);    /* send freq to latch */
  28.         outp(0x42,(int_pitch >> 8));
  29.         do {
  30.                 regs.x.ax = 0;       /* use timer to get end of duration */
  31.                 int86(0x1a, ®s, ®s);
  32.                 count = regs.x.dx;   /* use lowest 16-bits of count */
  33.         } while (count < int_duration + int_count);
  34.         v = inp(0x61) & 0xfc;        /* turn off the sound */
  35.         outp(0x61,v);
  36. }
  37.  
  38.  
  39.  
  40. [LISTING TWO]
  41.  
  42. #define outp(p,v) dx = p;al = v;asm(dx,al,"    out    dx,al")
  43. #define inp(p,v)  dx = p;asm(dx,"    in    al,dx",al);v = al
  44.     unsigned char x,y,page = 0; /* globals for pc_test */
  45. void note();
  46. main()
  47. {
  48.     note(440,500);
  49. }
  50.     
  51. void note(pitch, duration)
  52. int pitch,duration;
  53. {
  54.     reg$eax unsigned short ax;
  55.     reg$eax unsigned char al,x,y;
  56.     reg$edx unsigned short dx;
  57.     reg$ah    unsigned char ah;
  58.     /* this section was added for play */
  59.      unsigned int_count,int_duration,count,int_pitch;
  60.     if (duration == 0) return;
  61.         int_duration = (duration*1821)/10000;
  62. /*    We left the original interrupt as a comment for comparison purposes */
  63. /*      regs.x.ax = 0;       call timer */
  64. /*      int86(0x1a, ®s, ®s);  */
  65. /*      int_count = regs.x.dx; internal count = lowest 16-bits of time*/
  66. /*    the inline assembly language is line for line identical in function
  67.     although there is an obvious difference in format. */
  68.     ax = 0;
  69.     asm(ax,"    int    01ah",dx);
  70.     int_count = dx;
  71.  
  72.     if (pitch==0) goto time_it;
  73.     int_pitch = 1190000/pitch;
  74. /*    The port input is a little different using inline asm macros */
  75. /*    x = inp(0x61) | 3;    the original code becomes */    
  76.     inp(0x61,x);    /* Turn on channel 2 of 8253 using port 61H */    
  77.     x = x | 3;    /* After read turn on lowest 2 bits */
  78. +/*    The outp macro looks just like the outp function */    
  79.        outp(0x61,x);          /* send byte to back */
  80.         outp(0x43,0xb6);       /* set up I/O register */
  81.         outp(0x42,(char) int_pitch);    /* send freq to latch */
  82.         outp(0x42,(int_pitch >> 8));
  83. time_it:
  84.     do {
  85.         ax = 0;        /* use timer to wait for end */
  86.         asm(ax,"    int    01ah",dx);
  87.         count = dx;
  88.     } while (count < int_duration + int_count);
  89.     inp(0x61,y);    /* Turn off channel 2 */
  90.     y = y & 0xfc;    /* use 1111 1100 to turn off lowest 2 bits only */
  91.     outp(0x61,y);
  92. }
  93.  
  94.  
  95.  
  96. [LISTING THREE]
  97.  
  98.     name sound4.c
  99.     .387
  100.     assume    cs:codeseg
  101.     assume    ds:dataseg
  102. codeseg    segment dword er use32 public 'code'
  103. dataseg    segment dword rw use32 public 'data'
  104.  
  105. dataseg    ends
  106.     align    4
  107.  
  108. _note    proc    near
  109.  
  110.     push        edi
  111.     push        esi
  112.     push        ebx
  113.     mov        ebx,[esp]+16
  114.     cmp        dword ptr [esp]+20,0
  115.     jne        L17    short
  116.     pop        ebx
  117.     pop        esi
  118.     pop        edi
  119.     ret
  120.     align    4
  121. L17:
  122.     mov        ecx,10000
  123.     imul        eax,[esp]+20,1821
  124.     cdq
  125.     idiv        ecx
  126.     mov        edi,eax
  127.     mov        ax,0
  128.     int        01ah
  129.     movzx    esi,dx
  130.     or        ebx,ebx
  131.     jne        L16    short
  132.     jmp        L13
  133.     align    4
  134. L16:
  135.     mov        eax,1190000
  136.     cdq
  137.     idiv        ebx
  138.     mov        ebx,eax
  139.     mov        dx,97
  140.     in        al,dx
  141.     or        al,3
  142.     mov        dx,97
  143.     out        dx,al
  144.     mov        dx,67
  145.     mov        al,182
  146.     out        dx,al
  147.     mov        dx,66
  148.     mov        al,bl
  149.     out        dx,al
  150.     mov        dx,66
  151.     mov        eax,ebx
  152.     shr        eax,byte ptr 8
  153.     out        dx,al
  154.     align    4
  155. L14:
  156.     align    4
  157. L13:
  158.     mov        ax,0
  159.     int        01ah
  160.     movzx    ecx,dx
  161.     mov        eax,edi
  162.     add        eax,esi
  163.     cmp        eax,ecx
  164.     ja        L13    short
  165.     mov        dx,97
  166.     in        al,dx
  167.     and        al,252
  168.     mov        dx,97
  169.     out        dx,al
  170.     align    4
  171. L9:
  172.     pop        ebx
  173.     pop        esi
  174.     pop        edi
  175.     ret
  176.     align    4
  177. _note    endp
  178. dataseg    segment dword rw use32 public 'data'
  179.  
  180. ;_ax            ax        local
  181. ;_al            al        local
  182. ;_x            al        local
  183. ;_y            al        local
  184. ;_dx            dx        local
  185. ;_ah            ah        local
  186. ;_int_count    esi        local
  187. ;_int_duration    edi        local
  188. ;_count        ecx        local
  189. ;_int_pitch    ebx        local
  190.  
  191. ;parameters
  192. ;_pitch        ebx        local
  193. ;_duration    [esp]+20    local
  194. dataseg    ends
  195.     end
  196.  
  197.  
  198.  
  199.  
  200. [LISTING FOUR] 
  201.  
  202. #include <stdio.h>
  203. #include <dos1.h>
  204. #include <ctype.h>
  205. /*    ***WARNING*** if you change the scale so that it starts 
  206.     on middle C, instead of A, the resulting routine will 
  207.     exhibit not only the look and feel of the BASIC PLAY 
  208.     command, but its sound as well.
  209. */
  210. #define aa    440        /* middle a = 440 */
  211. #define as    469        /* a sharp */
  212. #define bb    493
  213. #define cc    523        /* middle c */
  214. #define cs    556
  215. #define dd    587
  216. #define ds    624
  217. #define ee    659
  218. #define ff    698
  219. #define fs    739
  220. #define gg    783
  221. #define gs    832
  222.  
  223. #define outp(p,v) dx = p;al = v;asm(dx,al,"    out    dx,al")
  224. #define inp(p,v)  dx = p;asm(dx,"    in    al,dx",al);v = al
  225.     unsigned char x,y,page = 0; /* globals for pc_test */
  226. void note();
  227. void look_ahead_and_toot();
  228. void play();
  229. int check_length();
  230. int check_integer();
  231. int gobble_dots();
  232.         /* the buffer for the notes to be input */
  233. int  pitch;            
  234. int  count = 0;            /* points to current location in string */
  235. int  length = 4;            /* default is a quarter note */
  236. int  tempo = 240;        /* = 120 beats per minute */
  237. int  duration = 60;        /* = tempo/length =1/4 @ 120 bpm */
  238. int  shift = 0;            /* current octave shift factor */
  239. char c_note;            /* the current note character used for diag */
  240.  
  241. main()
  242. {    /* Stereo version of Heart and Soul for two PCs
  243.     lifted from a BASIC program Transcribed by 
  244.     Michael Benjamin Fried - Age 11 */
  245.     /* bass line plays on first machine */
  246.     play( "T150L8O4CCEEAACCDDFFO3GG>BBO4");    
  247.     play( "L8O4CCEEAACCDDFFO3GG>BBO4");    
  248.  
  249.     /* while melody plays on a second */
  250.     play( "O4L4CCC.P32C8B8A8B8C8D8P32");
  251.     play( "EEE.P32E8D8C8D8E8F8G.C.>A8<G8F8E8D8CB8Ao3G8FFGGo4");
  252. }
  253. void play(in_string)
  254. char in_string[];
  255. {
  256. int temp_duration;        /* gets set by L or change in l */
  257. int temp_octave;        /* holds temporary octave */
  258. char    n_note;
  259. count = 0;
  260. printf("note = %s \n",in_string);
  261. while (c_note = in_string[count]){ /* loop till out of characters */ 
  262.     n_note = in_string[count+1];  /* look ahead 1 char now */
  263.     switch(c_note){            /* switch on current note */
  264.  
  265.         case 'A':        /* do a,a sharp and a flat */
  266.         case 'a':
  267.             pitch = aa;    /* set the default to A natural */
  268.             if ((n_note == '#')||(n_note == '+')){
  269.                 pitch = as; /* it was A sharp */
  270.                 count++;
  271.                 }
  272.             if (n_note == '-'){ /* it was A flat */
  273.                 pitch = gs; /* A flat == G sharp */
  274.                 count++;
  275.                 }
  276.             look_ahead_and_toot(in_string); /* self explanatory */
  277.             break;                 /* line duration */
  278.  
  279.         case 'B':        /* B is just like A */
  280.         case 'b':
  281.             pitch = bb;
  282.             if ((n_note == '#')||(n_note == '+')){
  283.                 pitch = cc; /* B sharp is actually C */
  284.                 count++;
  285.                 }
  286.             if (n_note == '-'){
  287.                 pitch = as; /* B flat is A sharp */
  288.                 count++;
  289.                 }
  290.             look_ahead_and_toot(in_string);
  291.             break;
  292.             
  293.         case 'C':            /* C is just like A */
  294.         case 'c':
  295.             pitch = cc;
  296.             if ((n_note == '#')||(n_note == '+')){
  297.                 pitch = cs;
  298.                 count++;
  299.                 }
  300.             if (n_note == '-'){ /* C flat is actually B */
  301.                 pitch = bb; /* and a perfectly legal note */
  302.                 count++;
  303.                 }
  304.             look_ahead_and_toot(in_string);
  305.             break;
  306.             
  307.         case 'D':        /* D is like A */
  308.         case 'd':
  309.             pitch = dd;
  310.             if ((n_note == '#')||(n_note == '+')){
  311.                 pitch = ds;
  312.                 count++;
  313.                 }
  314.             if (n_note == '-'){
  315.                 pitch = cs; /* D flat is C sharp */
  316.                 count++;
  317.                 }
  318.             look_ahead_and_toot(in_string);
  319.             break;
  320.             
  321.         case 'E':        /* E is like A */
  322.         case 'e':
  323.             pitch = ee;
  324.             if ((n_note == '#')||(n_note == '+')){
  325.                 pitch = ff; /* E sharp is F */
  326.                 count++;
  327.                 }
  328.             if (n_note == '-'){
  329.                 pitch = ds;
  330.                 count++;
  331.                 }
  332.             look_ahead_and_toot(in_string);
  333.             break;
  334.             
  335.         case 'F':        /* F is like A */
  336.         case 'f':
  337.             pitch = ff;
  338.             if ((n_note == '#')||(n_note == '+')){
  339.                 pitch = fs;
  340.                 count++;
  341.                 }
  342.             if (n_note == '-'){
  343.                 pitch = ee;
  344.                 count++;
  345.                 }
  346.             look_ahead_and_toot(in_string);
  347.             break;
  348.             
  349.         case 'G':        /* G is like A */
  350.         case 'g':
  351.             pitch = gg;
  352.             if ((n_note == '#')||(pitch == '+')){
  353.                 pitch = gs;
  354.                 count++;
  355.                 }
  356.             if (n_note == '-'){
  357.                 pitch = fs;
  358.                 count++;
  359.                 }
  360.             look_ahead_and_toot(in_string);
  361.             break;
  362.  
  363.         case 'L':        /* set length */
  364.         case 'l':
  365.             if(temp_duration = check_length(in_string)){
  366.                 duration = tempo/temp_duration;
  367.                 length = temp_duration;
  368.                 }
  369.             break;
  370.         case '>':        /* go up an octave */
  371.             shift++;
  372.             break;
  373.  
  374.         case '<':        /* go down an octave */
  375.             shift--;
  376.             break;
  377.                         
  378.         case 'O':        /* chose an octave */
  379.         case 'o':
  380.             temp_octave = n_note - '0';
  381.             if ((temp_octave < 0)||(temp_octave > 6)){
  382.                 printf("octave out of range");
  383.                 break;
  384.                 }
  385.             switch(n_note){
  386.                 case '0':
  387.                     shift = -4;
  388.                     break;
  389.                 case '1':
  390.                     shift = -3;
  391.                     break;
  392.                 case '2':
  393.                     shift = -2;
  394.                     break;
  395.                 case '3':
  396.                     shift = -1;
  397.                     break;
  398.                 case '4':        /* default octave */
  399.                     shift = 0;
  400.                     break;
  401.                 case '5':
  402.                     shift = 1;
  403.                     break;
  404.                 case '6':
  405.                     shift = 2;
  406.                     break;
  407.                 }
  408.             count++;    /* advance over digit */
  409.             break;
  410.         
  411.         case 'P':        /* set pause/rest length */
  412.         case 'p':        /* issue note of freq 0 to rest */
  413.         case 'R':        /* computer scientists pause */
  414.         case 'r':        /* but musicians rest! */
  415.             pitch = 0;
  416.             look_ahead_and_toot(in_string);
  417.             break;            
  418.             
  419.         case 'T':        /* set tempo */
  420.         case 't':
  421.             temp_duration = check_integer(in_string);
  422.             if ((temp_duration < 32)||(temp_duration > 255)) 
  423.                 break;
  424.             tempo = temp_duration*2;
  425.             duration = tempo/length;
  426.             break;
  427.  
  428.         case ' ':        /* spaces are gobbled up */
  429.             break;
  430.         
  431.         default:        /* had a problem so issue error */
  432.             printf("Syntax error in character %d \n",count);
  433.             goto terminate;
  434.         }
  435.     count++;    /* advance pointer to next note */
  436.     }
  437. terminate:
  438. }
  439. /* The trickiest part of the syntax are the optional trailers that
  440.     can follow each note. These include an optional integer that
  441.     specifies a quarter (4) or eighth note (8) (or any integer 
  442.     between 1 and 64) and 1 or more optional dots, each of which
  443.     increases the current duration by half. This section parses
  444.     these trailers, and then uses the global variables that contain
  445.     the tempo and octave to compute the duration and pitch, and
  446.     then call note. Note that rests are handled as notes of 0 pitch.
  447. */
  448.  
  449. void look_ahead_and_toot(in_string)
  450. char in_string[];
  451. {
  452. int temp_duration;
  453. if (temp_duration = check_length(in_string)) /* if non zero have a temp */
  454.     temp_duration = tempo/temp_duration;  /* compute new duration */
  455. else
  456.     temp_duration = duration;        /* if 0 play default duration */
  457. /* check for dot, and if found call gobble_dots to increase temp_duration */
  458. if (in_string[count+1] == '.') 
  459.     temp_duration = gobble_dots(temp_duration,in_string);
  460.         /* range check octaves */
  461. if (shift < -4)
  462.     shift = -4;
  463. if (shift > 2)
  464.     shift = 2;
  465.         /* shift to change octaves */
  466. if (shift < 0)    /* negative shifts go down in frequency */
  467.     pitch = pitch >> -shift;
  468. else        /* positive shifts go up in frequency */
  469.     pitch = pitch << shift;
  470.     /* optional diagnostics for debugging */
  471. printf("%c = %d duration = %d octave = d\n",
  472.             c_note,pitch,temp_duration,shift+4);
  473.     /* finally we are ready for a little toot */
  474. note(pitch,temp_duration);
  475. }
  476. int gobble_dots(duration_in,in_string)
  477. int duration_in;
  478. char in_string[];
  479. {
  480. int duration_out;
  481. int duration_increment;
  482. duration_out = duration_in;
  483. duration_increment = duration_in;
  484. /* gobble as long as there are dots adding half the prior duration inc */
  485. while (in_string[count+1] == '.'){
  486.     duration_increment = duration_increment >> 1; /* divide it by 2 */
  487.     duration_out = duration_out + duration_increment;
  488.     count++;            /* advance string pointer */ 
  489.     }
  490. return(duration_out);
  491. }
  492. /* returns 1-64 in range 1-64 else returns 0 */
  493. int check_length(in_string)
  494. char in_string[];
  495. {
  496. int result = check_integer(in_string);
  497.     if ((result < 1) || (result > 64)) 
  498.         return(0);    /* out of range */
  499.     else
  500.         return(result); /* in range */
  501. }
  502. /* 0 1 to 999 if 1 - 999 found and advances count */
  503. /* returns 0 otherwise */
  504. int check_integer(in_string)
  505. char in_string[];
  506. {
  507. int n_char,m_char,l_char;
  508. n_char = in_string[count+1] - '0';
  509. if ((n_char > 9) || (n_char < 0)) return (0); /* return if out of range */
  510. count++;             /* we found a digit so advance count */
  511. m_char = in_string[count+1] - '0';   /* check next integer */
  512. if ((m_char > 9) || (m_char < 0)) 
  513.     return (n_char);
  514. else 
  515.     count++;        /*found second didit so advance again */
  516. l_char = in_string[count+1] - '0';
  517. if ((l_char > 9) || (l_char < 0)) /* check last possible digit */
  518.     return (n_char*10+m_char); /* compute 2 digit result */
  519. else {
  520.     count++;        /* we found a third and last digit */
  521.     return(n_char*100+m_char*10+l_char);
  522.     }
  523. }
  524. /* optional main program works as an interactive interpreter */
  525. char note_string[120]; 
  526. /*
  527. main()
  528. {
  529. do{
  530.     puts("enter note ");
  531.     fflush(stdin);
  532.     gets(note_string);
  533.     printf("\nnote string = %s \n",note_string);
  534.     play();
  535.     } while (strlen(note_string) > 0);
  536. }
  537. */
  538.  
  539.  
  540.  
  541. [EXAMPLE 1]
  542.  
  543. char *mapdev();
  544. main()
  545. {
  546.     int jcount = 0;
  547.     char *scr_ptr;
  548.     /* map the screen into the data segment */
  549.     scr_ptr = mapdev(0xb8000,4096);
  550.     while (jcount < 4096)           
  551.     {
  552.         *(scr_ptr + (jcount++)) = 0x20; /* write space*/ 
  553.         *(scr_ptr + (jcount++)) = 0x7c; /* and attribute*/
  554.     }
  555. }
  556.  
  557.  
  558.  
  559.  
  560.